<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Calendar</title>
</head>

<body>
  <h1>演示</h1>
  <div class="demo">
    <div class="card">
      <div class="item item1"><span class="text">4</span></div>
      <div class="item item2"><span class="text">4</span></div>
      <div class="item item3"><span class="text">3</span></div>
      <div class="item item4"><span class="text">3</span></div>
    </div>
  </div>

  <h1>时间</h1>
  <div class="container">
    <div class="hours_high card">
      <div class="item item1"><span class="text">0</span></div>
      <div class="item item2"><span class="text">0</span></div>
      <div class="item item3"><span class="text">0</span></div>
      <div class="item item4"><span class="text">0</span></div>
    </div>
    <div class="hours_low card">
      <div class="item item1"><span class="text">0</span></div>
      <div class="item item2"><span class="text">0</span></div>
      <div class="item item3"><span class="text">0</span></div>
      <div class="item item4"><span class="text">0</span></div>
    </div>

    <div class="divider">:</div>

    <div class="minutes_high card">
      <div class="item item1"><span class="text">0</span></div>
      <div class="item item2"><span class="text">0</span></div>
      <div class="item item3"><span class="text">0</span></div>
      <div class="item item4"><span class="text">0</span></div>
    </div>
    <div class="minutes_low card">
      <div class="item item1"><span class="text">0</span></div>
      <div class="item item2"><span class="text">0</span></div>
      <div class="item item3"><span class="text">0</span></div>
      <div class="item item4"><span class="text">0</span></div>
    </div>

    <div class="divider">:</div>

    <div class="seconds_high card">
      <div class="item item1"><span class="text">0</span></div>
      <div class="item item2"><span class="text">0</span></div>
      <div class="item item3"><span class="text">0</span></div>
      <div class="item item4"><span class="text">0</span></div>
    </div>
    <div class="seconds_low card">
      <div class="item item1"><span class="text">0</span></div>
      <div class="item item2"><span class="text">0</span></div>
      <div class="item item3"><span class="text">0</span></div>
      <div class="item item4"><span class="text">0</span></div>
    </div>
  </div>

  <style>
    :root {
      --size: 120px;
      --item-width: 84px;
      --item-height: 120px;
      --bg-color: bisque;
      --text-color: #111;
    }

    .card {
      position: relative;
      margin: 0 1px;
      color: var(--text-color);
      background-color: var(--bg-color);
      width: var(--item-width);
      height: var(--item-height);
    }

    .card .item {
      background-color: var(--bg-color);
      width: 100%;
      height: 50%;
      left: 0;
      font-size: var(--size);
      top: 0;
      line-height: var(--size);
      overflow: hidden;
      text-align: center;
      position: absolute;
      transition: 0.9s;
    }

    .card .item1 {
      z-index: 0;
    }

    .card .item2 {
      top: 50%;
      line-height: 0;
      z-index: 1;
      border-top: 2px solid white;
      transform: rotateX(0deg);
      backface-visibility: hidden;
      transform-origin: 0% 0%;
    }

    .card .item3 {
      z-index: 1;
      border-bottom: 2px solid white;
      transform: rotateX(180deg);
      backface-visibility: hidden;
      transform-origin: 0% 100%;
    }

    .card .item4 {
      z-index: 0;
      top: 50%;
      line-height: 0;
    }

    .demo .card:hover .item2 {
      transform: rotateX(180deg);
    }

    .demo .card:hover .item3 {
      transform: rotateX(0deg);
    }

    .container {
      display: flex;
      align-items: center;
      font-size: var(--size);
    }

    .container .divider {
      min-width: 4px;
    }
  </style>

  <script>
    const area = {
      h: "hours",
      s: "seconds",
      m: "minutes"
    }
    const position = {
      l: "low",
      h: "high"
    }
    const dom = {
      container: document.querySelector(".container"),
      get: (a = "s", p = "l", is = []) => {
        if (Array.isArray(is)) {
          return document.querySelectorAll(is.map(i => `.container .card.${area[a]}_${position[p]} .item${i}`).join(","))
        }
        return document.querySelectorAll(`.container .card.${area[a]}_${position[p]} .item${is}`)
      }
    }

    function pipe(v, ...funcs) {
      return funcs.reduce((a, func) => func(a), v)
    }

    function separate(v) {
      return [v % 10, ~~(v / 10)]
    }

    function cut(max) {
      return (v) => (v >= max) ? (v % max) : v
    }

    const cut60 = cut(60);
    const cut24 = cut(24);
    const cut12 = cut(12);

    let pre = [0, 0, 0]
    function render() {
      const date = new Date();
      const H = date.getHours();
      const m = date.getMinutes();
      const s = date.getSeconds();

      const [hl, hh] = pipe(H, cut60, separate)
      const [ml, mh] = pipe(m, cut60, separate)
      const [sl, sh] = pipe(s, cut60, separate)

      const [phh, phl, pmh, pml, psh, psl] = pre;
      if (phh != hh) {
        animate("h", "h", phh, hh)
      }
      if (phl != hl) {
        animate("h", "l", phl, hl)
      }
      if (pmh != mh) {
        animate("m", "h", pmh, mh)
      }
      if (pml != ml) {
        animate("m", "l", pml, ml)
      }
      if (psh != sh) {
        animate("s", "h", psh, sh)
      }
      if (psl != sl) {
        animate("s", "l", psl, sl)
      }

      pre = [hh, hl, mh, ml, sh, sl]
    }

    function transition(a, p) {
      dom.get(a, p, 2).forEach(node => {
        node.style.transform = 'rotateX(0deg)'
        node.style.transition = 'none'
      })
      dom.get(a, p, 3).forEach(node => {
        node.style.transform = 'rotateX(180deg)'
        node.style.transition = 'none'
      })
      dom.container.clientWidth // trigger reflow
      dom.get(a, p, 2).forEach(node => {
        node.style.transition = '0.9s'
        node.style.transform = 'rotateX(180deg)'
      })
      dom.get(a, p, 3).forEach(node => {
        node.style.transition = '0.9s'
        node.style.transform = 'rotateX(0deg)'
      })
    }

    function text(a, p, v1, v2) {
      dom.get(a, p, [1, 2]).forEach(node => {
        node.textContent = v1
      })
      dom.get(a, p, [3, 4]).forEach(node => {
        node.textContent = v2
      })
    }

    function animate(a, p, v1, v2) {
      text(a, p, v1, v2)
      transition(a, p)
    }

    !(function main() {
      render()
      setInterval(render, 1000)
    })()
  </script>

  <footer>made by zpj 2023-3-1</footer>
</body>

</html>